package com.software.usercenter.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.json.JSONObject;
import com.software.usercenter.entity.*;
import com.software.usercenter.entity.Record;
import com.software.usercenter.exception.BizException;
import com.software.usercenter.feignclient.QuestionCenterFeignClient;
import com.software.usercenter.judge.Task;
import com.software.usercenter.repository.RecordRepository;
import com.software.usercenter.repository.UserRepository;
import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestParam;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import com.software.usercenter.judge.JudgeMethod;

/**
 * Author: zk
 * Description: 用户User服务层实现类
 */
@Service
public class UserServiceImpl implements UserService{
    @Autowired
    private UserRepository userRepository;
    @Autowired
    private RecordRepository recordRepository;
    @Autowired
    private QuestionCenterFeignClient questionCenterFeignClient;
    @Autowired
    private Task task;

    //注册的方法
    @Override
    public User register(User user) {
        Optional<User> optional=userRepository.findById(user.getId());
        if(optional.isPresent()==false){
            User save = userRepository.save(user);
            return save;
        }else{
            throw new BizException("该用户已经被注册了");
        }
    }

    //登录的方法
    @Override
    public User login(User user) {
        Optional<User> optional = userRepository.findById(user.getId());
        if(optional.isPresent()){
            User existUser = optional.get();
            if(user.getPassword().equals(existUser.getPassword())){
                return existUser;
            }else{//否则抛出自定义异常 密码错误
                throw new BizException("密码错误");
            }
        }else{
            throw new BizException("该用户不存在");
        }
    }
    //根据id查找全部个人信息
    @Override
    public User findUserById(String id) {
        Optional<User> optional=userRepository.findById(id);
        if(optional.isPresent()){
            return optional.get();
        }else{
            throw new BizException("该用户不存在");
        }
    }
    //根据个人id查询排行和个人信息的方法
    @Override
    public RankUser queryOwnRank(User user) {
        Optional<User> optional = userRepository.findById(user.getId());
        if(optional.isPresent()){
            Sort.Order order=Sort.Order.desc("acCount");
            Sort sort=Sort.by(order);
            //根据题目数倒序查出user的List集合
            List<User> userList = userRepository.findAll(sort);
            //循环遍历List集合
            //创建RankUser对象
            RankUser rankUser=new RankUser();
            for(int i=0;i<userList.size();i++){
                //当List集合对象的id等于我们传的id
                if(userList.get(i).getId().equals(user.getId())){
                    //把我们传的id的对象查出来
                    User temp=optional.get();
                    //创建一个UserDTO 把对象复制过去
                    UserDTO userDTO=new UserDTO();
                    BeanUtil.copyProperties(temp,userDTO);
                    //给rankUser设置对应属性
                    rankUser.setUserDTO(userDTO);
                    rankUser.setRank(i+1);
                    return rankUser;
                }
            }
        }
        throw new BizException("该用户不存在!");
    }


    //修改个人信息的方法
    //昵称 性别  AC题数
    @Override
    public void updateUserById(User user) {
        Optional<User> optional = userRepository.findById(user.getId());
        if(optional.isPresent()){
            User temp = optional.get();
            temp.setGender(user.getGender());
            temp.setUsername(user.getUsername());
            if (user.getAcCount() != null) {
                temp.setAcCount(user.getAcCount());
            }
            userRepository.save(temp);
        }else{
            throw new BizException("修改个人信息失败");
        }
    }

    //修改密码的方法
    @Override
    public void updatePassword(User user) {
        Optional<User> optional = userRepository.findById(user.getId());
        if(optional.isPresent()){
            User temp = optional.get();
            temp.setPassword(user.getPassword());
            userRepository.save(temp);
        }else{
            throw new BizException("修改密码失败");
        }
    }


    //发布题解的方法
    @Override
    public JSONObject publishAnswer(Answer answer) {
        answer.setId(UUID.randomUUID().toString());
        JSONObject insertAnswer=questionCenterFeignClient.insertAnswer(answer);
        return insertAnswer;
    }
    //查看题解列表的方法 分页
    @Override
    public JSONObject queryAnswerList(@RequestParam("questionId") Integer questionId, @RequestParam("pageNum") Integer pageNum, @RequestParam("size") Integer size) {
        JSONObject restPage = questionCenterFeignClient.queryAnswerList(questionId,pageNum,size);
        return restPage;
    }
    //查看具体题解的方法
    @Override
    public JSONObject queryAnswer(String answerId) {
        JSONObject detailAnswer=questionCenterFeignClient.queryAnswer(answerId);
        return detailAnswer;
    }
    //提交代码涉及的插入答题记录的方法
    @Override
    public Record insertRecord(Record record) {
//        System.out.println(record.toString());
//        System.out.println("questionId: " + record.getQuestionId());
        // 1.评测代码
        JSONObject questionJson = questionCenterFeignClient.findById(record.getQuestionId());
        Question question = questionJson.getBean("data", Question.class);
        System.out.println(question.toString());
        String language = record.getLanguage();
        Record result = null;
        try {
            switch (language) {
                case "java":
                    if(JudgeMethod.checkJavaCodeSafe(record.getAnswer().toLowerCase())){
                        result = task.compileAndRunJava(question, record);
                        break;
                    }else{
                        Record errorRecord = record;
                        errorRecord.setStatus("含有非法输入！");
                        return errorRecord;
//                        throw new BizException("用户输入非法代码");
                    }
                case "c":
                    if(JudgeMethod.checkCCodeSafe(record.getAnswer().toLowerCase())){
                        result = task.compileAndRunC(question, record);
                        break;
                    }else{
                        Record errorRecord = record;
                        errorRecord.setStatus("含有非法输入！");
                        return errorRecord;
//                        throw new BizException("用户输入非法代码");
                    }
                case "c++":
                    if(JudgeMethod.checkCCodeSafe(record.getAnswer().toLowerCase())){
                        result = task.compileAndRunCPlusPlus(question, record);
                        break;
                    }else{
                        Record errorRecord = record;
                        errorRecord.setStatus("含有非法输入！");
                        return errorRecord;
//                        throw new BizException("用户输入非法代码");
                    }
                case "python":
                    if(JudgeMethod.checkPythonCodeSafe(record.getAnswer().toLowerCase())){
                        result = task.compileAndRunPython(question, record);
                        break;
                    }else{
                        Record errorRecord = record;
                        errorRecord.setStatus("含有非法输入！");
                        return errorRecord;
//                        throw new BizException("用户输入非法代码");
                    }
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        // 2.用户ac题数+1
        // 1)查询用户
        User user = null;
        Optional<User> optional = userRepository.findById(record.getUserId());
        if (optional.isPresent()) {
            user = optional.get();
        }

        boolean flag = false;
        if (user != null) {
            // 2)判断用户是否答对过此题
            List<Record> records = queryOwnRecordList(user.getId(), record.getQuestionId());
            if (records != null && records.size() != 0) {
                for (Record r : records) {
                    if (r.getStatus().equals("Accepted")) {
                        flag = true;
                        break;
                    }
                }
            }
            // 3)增加ac题数, 并更新数据库
            if (!flag && result.getStatus().equals("Accepted")) {
                user.setAcCount(user.getAcCount() + 1);
                updateUserById(user);
            }
            System.out.println("AC题数: " + user.getAcCount());
        }
        // 3.更新数据库中的答题记录
        recordRepository.save(result);

        return record;
    }

    //查询题目所有答题记录的方法
    @Override
    public Page queryRecordList(String userId, Integer questionId,Pageable pageable) {
        Specification<Record> specification = new Specification<Record>() {
            @Override
            public Predicate toPredicate(Root<Record> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                //添加判断 找到用户id和题目id和答题记录表里都一样的记录
                if (!StringUtils.isEmpty(userId)) {
                    predicates.add(criteriaBuilder.equal(root.get("userId"), userId));
                }
                if (!StringUtils.isEmpty(questionId)) {
                    predicates.add(criteriaBuilder.equal(root.get("questionId"),questionId));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        Page page=recordRepository.findAll(specification,pageable);
        return page;
    }
    //不需要分页的 查询用户关于某个题目的答题记录的方法
    @Override
    public List<Record> queryOwnRecordList(String userId, Integer questionId) {
        Specification<Record> specification = new Specification<Record>() {
            @Override
            public Predicate toPredicate(Root<Record> root, CriteriaQuery<?> criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> predicates = new ArrayList<>();
                //添加判断 找到用户id和题目id和答题记录表里都一样的记录
                if (!StringUtils.isEmpty(userId)) {
                    predicates.add(criteriaBuilder.equal(root.get("userId"), userId));
                }
                if (!StringUtils.isEmpty(questionId)) {
                    predicates.add(criteriaBuilder.equal(root.get("questionId"),questionId));
                }
                return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
            }
        };
        //按照用户的答题时间排序  降序排列 后提交的记录在前面
        Sort.Order order=Sort.Order.desc("createTime");
        Sort sort=Sort.by(order);
        List list = recordRepository.findAll(specification, sort);
        return list;
    }

    //查看具体答题记录的方法
    @Override
    public Record queryRecord(Integer recordId) {
        try{
            //如果不发生异常 说明查询到数据了
            Optional<Record> optional=recordRepository.findById(recordId);
            Record existRecord = optional.get();
            return existRecord;
        }catch(NullPointerException e){
            //发生异常证明数据库中没有这条答题记录
            throw new BizException("没有查询到这条答题记录");
        }
    }

    //查询排行的方法
    @Override
    public Page queryRank(Pageable pageable) {
        Page page=userRepository.findAll(pageable);
        return page;
    }

}
